import javax.swing.*;
import java.util.*;
import java.text.*;
import java.awt.*;
import java.awt.event.*;
import com.lavantech.gui.comp.*;
import java.sql.*;

/**
 * A JDialog for adding and editing goals.
 *
 * @author Jacel Evasco
 * @author Roselle Nympha Lim
 * @author Christian Paul Rosquita
 * @version 1.0
 */
public class GoalEditor extends JDialog {

    private boolean isInEditMode = false;
    private JLabel background = new JLabel(new ImageIcon(
        "images\\backgrounds\\goalEditorBG.png"));
    private JPanel labels = new JPanel();
    private JPanel fields = new JPanel();
    private JPanel buttons = new JPanel();
    private JTextField name = new JTextField();
    private JComboBox requirement = new JComboBox();
    private DateTimePicker due = new DateTimePicker();
    private JComboBox status = new JComboBox();
    private JComboBox priority = new JComboBox();
    private JTextArea notes = new JTextArea();
    private JScrollPane notesScroller = new JScrollPane(notes);
    private JButton okay = new JButton("okay");
    private JButton cancel = new JButton("cancel");
    private JLabel[] fieldLabels = {
        new JLabel("Name", SwingConstants.RIGHT),
        new JLabel("Requirement", SwingConstants.RIGHT),
        new JLabel("Due", SwingConstants.RIGHT),
        new JLabel("Status", SwingConstants.RIGHT),
        new JLabel("Priority", SwingConstants.RIGHT),
        new JLabel("Notes", SwingConstants.RIGHT) };

    public GoalEditor() {
        assemble();
        configure();
        design();
        setTriggers();
        setVisible(false);
    }// end of GoalEditor()

    private void assemble() {
        // labels
        labels.setLayout(new BoxLayout(labels, BoxLayout.Y_AXIS));
        labels.add(Box.createRigidArea(new Dimension(0, 30)));
        labels.add(fieldLabels[0]);
        labels.add(Box.createRigidArea(new Dimension(0, 15)));
        labels.add(fieldLabels[1]);
        labels.add(Box.createRigidArea(new Dimension(0, 15)));
        labels.add(fieldLabels[2]);
        labels.add(Box.createRigidArea(new Dimension(0, 15)));
        labels.add(fieldLabels[3]);
        labels.add(Box.createRigidArea(new Dimension(0, 15)));
        labels.add(fieldLabels[4]);
        labels.add(Box.createRigidArea(new Dimension(0, 15)));
        labels.add(fieldLabels[5]);
        // buttons
        buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
        buttons.add(Box.createRigidArea(new Dimension(157, 0)));
        buttons.add(cancel);
        buttons.add(Box.createRigidArea(new Dimension(8, 0)));
        buttons.add(okay);
        // fields
        fields.setLayout(new BoxLayout(fields, BoxLayout.Y_AXIS));
        fields.add(Box.createRigidArea(new Dimension(0, 30)));
        fields.add(name);
        fields.add(Box.createRigidArea(new Dimension(0, 15)));
        fields.add(requirement);
        fields.add(Box.createRigidArea(new Dimension(0, 15)));
        fields.add(due);
        fields.add(Box.createRigidArea(new Dimension(0, 15)));
        fields.add(status);
        fields.add(Box.createRigidArea(new Dimension(0, 15)));
        fields.add(priority);
        fields.add(Box.createRigidArea(new Dimension(0, 15)));
        fields.add(notesScroller);
        fields.add(Box.createRigidArea(new Dimension(0, 15)));
        fields.add(buttons);
        // content
        background.setLayout(new BoxLayout(background,
            BoxLayout.X_AXIS));
        background.add(Box.createRigidArea(new Dimension(32, 0)));
        background.add(labels);
        background.add(Box.createRigidArea(new Dimension(31, 0)));
        background.add(fields);
        // to background
        setLayout(new BorderLayout());
        add(background);
        setTitle("Goal Editor");
        setSize(500, 550);
        setLocationRelativeTo(null);
        setResizable(false);
    }// end of assemble()

    private void configure() {
        setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
        due.setMinSelectableTime(new GregorianCalendar(Calendar
            .getInstance().get(Calendar.YEAR), Calendar.getInstance()
            .get(Calendar.MONTH), Calendar.getInstance().get(
            Calendar.DAY_OF_MONTH)));
        try {
            fetchStatuses();
            fetchPriorities();
            fetchRequirements();
        } catch (Exception noise) {
            noise.printStackTrace();
        }
        due.getTimePanel().setEnabled(false);
        due.getTimePanel().setEditable(false);
        due.setDisplayClock(false);
        due.setPattern("YYYY-MM-dd");
    }// end of configure()

    private void design() {
        // sizes
        fields.setPreferredSize(new Dimension(313, 550));
        fields.setMinimumSize(new Dimension(313, 550));
        fields.setMaximumSize(new Dimension(313, 550));
        labels.setPreferredSize(new Dimension(85, 550));
        labels.setMinimumSize(new Dimension(85, 550));
        labels.setMaximumSize(new Dimension(85, 550));
        fieldLabels[0].setPreferredSize(new Dimension(85, 28));
        fieldLabels[0].setMinimumSize(new Dimension(85, 28));
        fieldLabels[0].setMaximumSize(new Dimension(85, 28));
        fieldLabels[1].setPreferredSize(new Dimension(85, 28));
        fieldLabels[1].setMinimumSize(new Dimension(85, 28));
        fieldLabels[1].setMaximumSize(new Dimension(85, 28));
        fieldLabels[2].setPreferredSize(new Dimension(85, 28));
        fieldLabels[2].setMinimumSize(new Dimension(85, 28));
        fieldLabels[2].setMaximumSize(new Dimension(85, 28));
        fieldLabels[3].setPreferredSize(new Dimension(85, 28));
        fieldLabels[3].setMinimumSize(new Dimension(85, 28));
        fieldLabels[3].setMaximumSize(new Dimension(85, 28));
        fieldLabels[4].setPreferredSize(new Dimension(85, 28));
        fieldLabels[4].setMinimumSize(new Dimension(85, 28));
        fieldLabels[4].setMaximumSize(new Dimension(85, 28));
        fieldLabels[5].setPreferredSize(new Dimension(85, 28));
        fieldLabels[5].setMinimumSize(new Dimension(85, 28));
        fieldLabels[5].setMaximumSize(new Dimension(85, 28));
        okay.setPreferredSize(new Dimension(74, 28));
        okay.setMinimumSize(new Dimension(74, 28));
        okay.setMaximumSize(new Dimension(74, 28));
        cancel.setPreferredSize(new Dimension(74, 28));
        cancel.setMinimumSize(new Dimension(74, 28));
        cancel.setMaximumSize(new Dimension(74, 28));
        name.setPreferredSize(new Dimension(313, 28));
        name.setMinimumSize(new Dimension(313, 28));
        name.setMaximumSize(new Dimension(313, 28));
        requirement.setPreferredSize(new Dimension(313, 28));
        requirement.setMinimumSize(new Dimension(313, 28));
        requirement.setMaximumSize(new Dimension(313, 28));
        due.setPreferredSize(new Dimension(313, 28));
        due.setMinimumSize(new Dimension(313, 28));
        due.setMaximumSize(new Dimension(313, 28));
        status.setPreferredSize(new Dimension(313, 28));
        status.setMinimumSize(new Dimension(313, 28));
        status.setMaximumSize(new Dimension(313, 28));
        priority.setPreferredSize(new Dimension(313, 28));
        priority.setMinimumSize(new Dimension(313, 28));
        priority.setMaximumSize(new Dimension(313, 28));
        notesScroller.setPreferredSize(new Dimension(313, 201));
        notesScroller.setMinimumSize(new Dimension(313, 201));
        notesScroller.setMaximumSize(new Dimension(313, 201));
        // font styles
        Font font = new Font("Segoe UI Light", Font.PLAIN, 14);
        Font labelFont = new Font("Segoe UI", Font.BOLD, 13);
        Font buttonFont = new Font("Segoe UI", Font.BOLD, 13);
        name.setFont(font);
        requirement.setFont(font);
        due.setFont(font);
        status.setFont(font);
        priority.setFont(font);
        notes.setFont(font);
        okay.setFont(buttonFont);
        cancel.setFont(buttonFont);
        fieldLabels[0].setFont(labelFont);
        fieldLabels[1].setFont(labelFont);
        fieldLabels[2].setFont(labelFont);
        fieldLabels[3].setFont(labelFont);
        fieldLabels[4].setFont(labelFont);
        fieldLabels[5].setFont(labelFont);
        // borders
        name.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
        requirement.setBorder(BorderFactory.createLineBorder(
            Color.BLACK, 1));
        due.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
        status.setBorder(BorderFactory.createLineBorder(Color.BLACK,
            1));
        priority.setBorder(BorderFactory.createLineBorder(
            Color.BLACK, 1));
        notesScroller.setBorder(BorderFactory.createLineBorder(
            Color.BLACK, 1));
        // backgrounds
        labels.setOpaque(false);
        fields.setOpaque(false);
        buttons.setOpaque(false);

        name.setBackground(Color.WHITE);
        requirement.setBackground(Color.WHITE);
        due.setBackground(Color.WHITE);
        status.setBackground(Color.WHITE);
        priority.setBackground(Color.WHITE);
        notesScroller.setBackground(Color.WHITE);

        // buttons
        okay.setContentAreaFilled(false);
        cancel.setContentAreaFilled(false);

    }// end of design()

    private void setTriggers() {
        ActionListener actionTrigger = new ActionListener() {
            public void actionPerformed(ActionEvent anActionEvent) {
                if (anActionEvent.getSource() == okay) {
                    if (name.getText().equals("")) {

                        JOptionPane.showMessageDialog(null,
                            "Please name your goal.");
                    } else if (requirement.getSelectedItem() == null) {

                        JOptionPane.showMessageDialog(null,
                            "You have no requirements. "
                                + "Please add a requirement first.");
                    } else {
                        if (isInEditMode == false) {
                            try {
                                if (hasDuplicateForInsert()) {
                                    JOptionPane
                                        .showMessageDialog(
                                            null,
                                            "A goal with a similar name exists. "
                                                + "Please rename your goal.");
                                } else {
                                    insert();
                                    Explorer.getInstance()
                                        .getGoalsViewer().getData()
                                        .refresh();
                                    Explorer.getInstance()
                                        .getGoalsViewer()
                                        .isDataEmpty();
                                    Explorer.getInstance()
                                        .getRequirementsViewer()
                                        .isDataEmpty();
                                    JOptionPane
                                        .showMessageDialog(null,
                                            "Operation successful.");
                                    dispose();
                                }
                            } catch (Exception noise) {
                                noise.printStackTrace();
                                JOptionPane
                                    .showMessageDialog(
                                        null,
                                        "Something went wrong. "
                                            + "Please close this dialog and try again.");
                            }
                        } else {
                            try {
                                if (hasDuplicateForUpdate()) {
                                    JOptionPane
                                        .showMessageDialog(
                                            null,
                                            "A goal with a similar name exists. "
                                                + "Please rename your goal.");
                                } else {
                                    insert(Explorer.getInstance()
                                        .getGoalsViewer()
                                        .getSelectedID());
                                    Explorer.getInstance()
                                        .getGoalsViewer().getData()
                                        .refresh();
                                    Explorer.getInstance()
                                        .getRequirementsViewer()
                                        .getData().refresh();
                                    Explorer.getInstance()
                                        .getGoalsViewer()
                                        .isDataEmpty();
                                    Explorer.getInstance()
                                        .getRequirementsViewer()
                                        .isDataEmpty();
                                    JOptionPane
                                        .showMessageDialog(null,
                                            "Operation successful.");
                                    dispose();
                                }
                            } catch (Exception noise) {
                                noise.printStackTrace();
                                JOptionPane
                                    .showMessageDialog(
                                        null,
                                        "Something went wrong. "
                                            + "Please close this dialog and try again.");
                            }
                        }
                    }
                } else if (anActionEvent.getSource() == cancel) {
                    dispose();
                }
            }
        };// end of viewerTrigger

        ItemListener itemTrigger = new ItemListener() {
            public void itemStateChanged(ItemEvent anItemEvent) {
                if ((((status.getSelectedItem().toString())
                    .equalsIgnoreCase("done")) || ((status
                    .getSelectedItem().toString())
                    .equalsIgnoreCase("cancelled"))) == true) {
                    requirement.setEnabled(false);
                    due.setEnabled(false);
                    priority.setEnabled(false);
                } else {
                    requirement.setEnabled(true);
                    due.setEnabled(true);
                    priority.setEnabled(true);
                }
            }
        };// end of itemTrigger

        okay.addActionListener(actionTrigger);
        cancel.addActionListener(actionTrigger);
        status.addItemListener(itemTrigger);
    }// end of setTriggers

    private void insert() throws Exception {

        DatabaseUtility
            .executeQuery("INSERT INTO goal "
                + "(name, due, status, priority, notes, studentID, requirementID) "
                + "SELECT '"
                + name.getText()
                + "', '"
                + (new SimpleDateFormat("YYYY-MM-dd")).format(due
                    .getDate()) + "', '"
                + status.getSelectedItem().toString() + "', '"
                + priority.getSelectedItem().toString() + "', '"
                + notes.getText() + "', " + "student.studentID, "
                + "requirement.requirementID "
                + "FROM requirement JOIN student "
                + "ON requirement.studentID = student.studentID "
                + "WHERE student.isLoggedIn = 1 "
                + "AND requirement.name = '"
                + (requirement.getSelectedItem().toString()) + "' ");
    }// end of insert()

    private void insert(String goalID) throws Exception {
        DatabaseUtility.executeQuery("UPDATE goal "
            + "SET "
            + "goal.name = '"
            + name.getText()
            + "', "
            + "goal.due = '"
            + (new SimpleDateFormat("YYYY-MM-dd")).format(due
                .getDate())
            + "', "
            + "goal.status = '"
            + status.getSelectedItem().toString()
            + "', "
            + "goal.priority = '"
            + priority.getSelectedItem().toString()
            + "', "
            + "goal.notes = '"
            + notes.getText()
            + "', "
            + "goal.studentID = goal.studentID, "
            + "goal.requirementID = '"
            + getRequirementID(requirement.getSelectedItem()
                .toString()) + "' " + "WHERE " + "goal.goalID = "
            + goalID);
    }// end of insert()

    private String getRequirementID(String name) throws Exception {
        Connection connection = DatabaseUtility.prepareConnection();
        Statement statement = connection.createStatement();
        ResultSet results = statement
            .executeQuery("SELECT requirement.requirementID "
                + "FROM requirement " + "NATURAL JOIN student "
                + "WHERE student.isLoggedIn = 1 "
                + "AND requirement.name = '" + name + "' ");
        results.next();
        return results.getString(1);
    }// end of getRequirementID()

    private boolean hasDuplicateForInsert() {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        String verifyQuery = "SELECT * FROM requirementstrackerschema.goal"
            + " WHERE name = ? AND studentID = "
            + "(SELECT studentID FROM requirementstrackerschema.student "
            + "WHERE isLoggedIn = 1)";

        try {
            connection = DatabaseUtility.prepareConnection();
            preparedStatement = connection
                .prepareStatement(verifyQuery);
            preparedStatement.setString(1, name.getText());
            resultSet = preparedStatement.executeQuery();

            // if there is a duplicate
            if (resultSet.next()) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } // end of try-catch

        return false;
    }// end of hasDuplicateForInsert method

    private boolean hasDuplicateForUpdate() {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        String verifyQuery = "SELECT * FROM requirementstrackerschema.goal"
            + " WHERE name = ? AND goalID != ? AND studentID = "
            + "(SELECT studentID FROM requirementstrackerschema.student "
            + "WHERE isLoggedIn = 1)";

        try {
            connection = DatabaseUtility.prepareConnection();
            preparedStatement = connection
                .prepareStatement(verifyQuery);
            preparedStatement.setString(1, name.getText());
            preparedStatement.setString(2, Explorer.getInstance()
                .getGoalsViewer().getSelectedID());
            resultSet = preparedStatement.executeQuery();

            // if there is a duplicate
            if (resultSet.next()) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } // end of try-catch

        return false;
    }// end of hasDuplicateForUpdate method

    public void load(String goalID) throws Exception {

        String[][] temp = DatabaseUtility
            .getResults("SELECT goal.name, "
                + // [0][0]
                "requirement.name, "
                + // [0][1]
                "YEAR(goal.due), "
                + // [0][2]
                "MONTH(goal.due), "
                + // [0][3]
                "DAYOFMONTH(goal.due), "
                + // [0][4]
                "HOUR(goal.due), "
                + // [0][5]
                "MINUTE(goal.due), "
                + // [0][6]
                "goal.status, "
                + // [0][7]
                "goal.priority, "
                + // [0][8]
                "goal.notes "
                + // [0][9]
                "FROM goal "
                + "JOIN requirement "
                + "ON goal.requirementID = requirement.requirementID "
                + "JOIN student "
                + "ON requirement.studentID = student.studentID "
                + "WHERE student.isLoggedIn = 1 "
                + "AND goal.goalID = " + goalID);
        name.setText(temp[0][0]);
        requirement.setSelectedItem(temp[0][1]);
        due.setCalendar(new GregorianCalendar(Integer
            .parseInt(temp[0][2]), // year
            Integer.parseInt(temp[0][3]) - 1, // month
            Integer.parseInt(temp[0][4]), // day of month
            Integer.parseInt(temp[0][5]), // hour
            Integer.parseInt(temp[0][6]))); // minute
        status.setSelectedItem(temp[0][7]);
        priority.setSelectedItem(temp[0][8]);
        notes.setText(temp[0][9]);
    }// end of load()

    public void clear() {

        name.setText(null);
        requirement.setSelectedItem(0);
        due.setCalendar(new GregorianCalendar());
        status.setSelectedItem(1);
        priority.setSelectedItem(0);
        notes.setText(null);
    }// end of clear()

    public void fetchRequirements() throws Exception {

        requirement.removeAllItems();
        DatabaseUtility.prepareConnection();
        String[][] temp = DatabaseUtility
            .getResults("SELECT requirement.name "
                + "FROM requirement " + "JOIN student "
                + "ON requirement.studentID = student.studentID "
                + "WHERE student.isLoggedIn = 1");
        for (int row = 0; row < temp.length; row++) {
            requirement.addItem(temp[row][0]);
        }
    }// end of fetchRequirements()

    public void fetchStatuses() throws Exception {

        status.removeAllItems();
        DatabaseUtility.prepareConnection();
        String[][] temp = DatabaseUtility
            .getResults("SHOW COLUMNS from GOAL "
                + "WHERE field = 'status'");
        temp[0][1] = temp[0][1].substring(5,
            (temp[0][1].length() - 1));
        temp[0][1] = temp[0][1].replaceAll("'", "");
        for (int row = 0; row < (temp[0][1].split(",")).length; row++) {
            status.addItem((Arrays.asList(temp[0][1].split(",")))
                .get(row));
        }
        status.setSelectedItem("not done");
    }// end of fetchStatuses()

    public void fetchPriorities() throws Exception {

        priority.removeAllItems();
        DatabaseUtility.prepareConnection();
        String[][] temp = DatabaseUtility
            .getResults("SHOW COLUMNS from GOAL "
                + "WHERE field = 'priority'");
        temp[0][1] = temp[0][1].substring(5,
            (temp[0][1].length() - 1));
        temp[0][1] = temp[0][1].replaceAll("'", "");
        for (int row = 0; row < (temp[0][1].split(",")).length; row++) {
            priority.addItem((Arrays.asList(temp[0][1].split(",")))
                .get(row));
        }
    }// end of fetchPriorities()

    public void setEditMode(boolean value) {
        isInEditMode = value;
    }// end of setEditMode()
}// end of GoalEditor